package com.cd2cd.service.impl;

import java.io.*;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.sql.SQLException;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSONObject;
import com.cd2cd.comm.ServiceCode;
import com.cd2cd.dom.java.FileIdsAndType;
import com.cd2cd.dom.java.TypeEnum;
import com.cd2cd.domain.gen.*;
import com.cd2cd.util.*;
import com.cd2cd.util.mbg.DBUtil;
import com.cd2cd.util.project.MicroProjectGenerate;
import com.cd2cd.util.project.ProjectGenerate;
import com.cd2cd.util.project.SimpleProjectGenerate;
import com.cd2cd.domain.*;
import com.cd2cd.mapper.*;
import com.cd2cd.vo.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSONArray;
import com.cd2cd.service.ProProjectService;
import org.springframework.util.ResourceUtils;
import sun.net.www.protocol.file.FileURLConnection;

import javax.annotation.Resource;

import static com.cd2cd.util.DataCache.CacheEnumKeys.*;


@Service
public class ProProjectServiceImpl implements ProProjectService {

    private final static Logger LOG = LoggerFactory.getLogger(ProProjectServiceImpl.class);

    @Autowired
    private ProProjectMapper proProjectMapper;

    @Autowired
    private ProDatabaseMapper proDatabaseMapper;

    @Autowired
    private ProProjectDatabaseRelMapper proProjectDatabaseRelMapper;

    @Autowired
    private ProModuleMapper proModuleMapper;

    @Autowired
    private ProTableMapper proTableMapper;

    @Autowired
    private ProTableColumnMapper tableColumnMapper;

    @Autowired
    private ProFileMapper proFileMapper;

    @Autowired
    private ProFieldMapper proFieldMapper;

    @Autowired
    private ProFunMapper funMapper;

    @Autowired
    private ProFunArgMapper funArgMapper;

    @Autowired
    private CommValidateMapper commValidateMapper;

    @Resource
    private ProMicroServiceMapper microServiceMapper;


    @Override
    public BaseRes<DataPageWrapper<ProProjectVo>> list(Integer currPage, Integer pageSize, ProProjectVo proProjectVo) {

        BaseRes<DataPageWrapper<ProProjectVo>> res = new BaseRes<>();
        res.setData(new DataPageWrapper<>());
        res.getData().setCurrPage(currPage);
        res.getData().setPageSize(pageSize);

        ProProjectCriteria example = new ProProjectCriteria();
        int mysqlLength = pageSize;
        int mysqlOffset = (currPage - 1) * mysqlLength;

        example.setMysqlLength(mysqlLength);
        example.setMysqlOffset(mysqlOffset);

        ProProjectCriteria.Criteria mCriteria = example.createCriteria();
        mCriteria.andDelFlagEqualTo(0);
        if (StringUtils.isNotEmpty(proProjectVo.getName())) {
            mCriteria.andNameLike(proProjectVo.getName() + "%");
        }

        long totalCount = proProjectMapper.countByExample(example);
        res.getData().setTotalCount(totalCount);
        if (totalCount > 0) {
            List<ProProject> proProjectList = proProjectMapper.selectByExample(example);
            List<ProProjectVo> rows = BeanUtil.voConvertList(proProjectList, ProProjectVo.class);
            res.getData().setRows(rows);
        }
        return res;
    }

    @Override
    public ProProjectVo detail(Long id) {
        ProProject mProProject = proProjectMapper.selectByPrimaryKey(id);
        if (mProProject != null) {
            ProProjectVo mProProjectVo = BeanUtil.voConvert(mProProject, ProProjectVo.class);

            List<Long> dbIds = new ArrayList<Long>();

            // query project ref db list
            ProProjectDatabaseRelCriteria mProProjectDatabaseRelCriteria = new ProProjectDatabaseRelCriteria();
            mProProjectDatabaseRelCriteria.createCriteria().andProjectIdEqualTo(mProProjectVo.getId());
            List<ProProjectDatabaseRel> list = proProjectDatabaseRelMapper.selectByExample(mProProjectDatabaseRelCriteria);
            for (int i = 0; i < list.size(); i++) {
                dbIds.add(list.get(i).getDatabaseId());
            }

            mProProjectVo.setDbIds(dbIds);
            return mProProjectVo;
        }
        return null;
    }

    @Override
    public boolean del(Long projectId) {
        // delete project to db ref
        ProProjectDatabaseRelCriteria mProProjectDatabaseRelCriteria = new ProProjectDatabaseRelCriteria();
        mProProjectDatabaseRelCriteria.createCriteria().andProjectIdEqualTo(projectId);
        proProjectDatabaseRelMapper.deleteByExample(mProProjectDatabaseRelCriteria);

        // delete module

        // delete project file

        return proProjectMapper.deleteByPrimaryKey(projectId) > 0;
    }

    @Transactional
    @Override
    public ServiceCode add(ProProjectVo proProjectVo) throws IOException {
        ProProject proProject = BeanUtil.voConvert(proProjectVo, ProProject.class);
        proProject.setCreateTime(new Date());
        proProject.setUpdateTime(new Date());
        proProject.setIgnoreTables("");

        proProjectMapper.insertSelective(proProject);

        // insert project and database
        if (null != proProjectVo.getDbIds()) {
            updateProjectAndDatabaseRel(proProject.getId(), proProjectVo.getDbIds());
        }

        Long projectId = proProject.getId();
        String templateType = proProjectVo.getTemplateType();
        String proType = proProjectVo.getProType();
        String dbJson = proProjectVo.getDbJson();

        String genPath = "/template/" + templateType + "/file/";


        // 倒入对应的表结构
        importDatabase(genPath, dbJson);

        // 1、倒入对应数据库配置
        // 2、将controller fun_oid对应的fun_nid 存入到project conf_json中，供首次生成项目时替换使用
        importConfig(projectId, genPath, dbJson);

        return ServiceCode.SUCCESS;
    }

    private void importDatabase(String genPath, String dbJson) throws IOException {

        JSONObject dbObject = JSONObject.parseObject(dbJson);
        for (Map.Entry<String, Object> entry : dbObject.entrySet()) {

            JSONObject data = JSONObject.parseObject(entry.getValue().toString());

            Long dbId = data.getLong("id");

            String oldName = data.getString("oldName");

            ProDatabase database = proDatabaseMapper.selectByPrimaryKey(dbId);

            String path = genPath + oldName + "_init.json";

            String sql = readFileInResource(path);

            String host = database.getHostname();
            String port = database.getPort();
            String username = database.getUsername();
            String password = database.getPassword();
            String dbName = database.getDbName();
            LOG.info("database={}", JSONObject.toJSONString(database));

            DBUtil.exeMultipleSql(JSONArray.parseArray(sql).toArray(), host, Integer.parseInt(port), username, password, dbName);
        }

    }

    private String readFileInResource(String path) {
        LOG.info("configPath={}", path);
        InputStream json = ProProjectServiceImpl.class.getResourceAsStream(path);
        String data = null;
        try {
            data = IOUtils.toString(json, "utf-8");
        } catch (IOException e) {
            e.printStackTrace();
        }

        return data;

    }


    // dbJson :{"database_6":1,"database_9":2}
    private void importConfig(Long projectId, String genPath, String dbJson) throws IOException {
        // 读取对应的配置文件

        String path = genPath + "dataConfig.json";

        String s = readFileInResource(path);
        JSONObject configJson = JSONObject.parseObject(s);


        //倒入选择的项目配置
//        String projectStr = configJson.getJSONObject("project").toJSONString();
        String moduleStr = configJson.getJSONObject("module").toJSONString();
        String microStr = configJson.getJSONObject("micro").toJSONString();
        String tableStr = configJson.getJSONObject("table").toJSONString();
        String columnStr = configJson.getJSONObject("column").toJSONString();
        String fileStr = configJson.getJSONObject("file").toJSONString();
        String fieldStr = configJson.getJSONObject("field").toJSONString();
        String funStr = configJson.getJSONObject("fun").toJSONString();
        String funArgStr = configJson.getJSONObject("funArg").toJSONString();


        // 插入module 修改 file
        moduleStr = moduleStr.replaceAll("project_Id", projectId.toString());
        JSONObject moduleJson = JSONObject.parseObject(moduleStr);
        for (Map.Entry<String, Object> moduleEntry : moduleJson.entrySet()) {
            String key = moduleEntry.getKey();
            String value = moduleEntry.getValue().toString();
            ProModule proModule = JSONObject.parseObject(value, ProModule.class);
            proModule.setCreateTime(new Date());
            proModule.setUpdateTime(new Date());
            proModuleMapper.insertSelective(proModule);
            fileStr = fileStr.replaceAll(key, proModule.getId().toString());
        }

        // 插入 micro 修改 file
        microStr = microStr.replaceAll("project_Id", projectId.toString());
        JSONObject microJson = JSONObject.parseObject(microStr);
        for (Map.Entry<String, Object> microEntry : microJson.entrySet()) {
            String key = microEntry.getKey();
            String value = microEntry.getValue().toString();
            ProMicroService proMicroService = JSONObject.parseObject(value, ProMicroService.class);
            proMicroService.setCreateTime(new Date());
            proMicroService.setUpdateTime(new Date());
            microServiceMapper.insertSelective(proMicroService);
            fileStr = fileStr.replaceAll(key, proMicroService.getId().toString());
        }

        // 修改 table
        JSONObject dbObject = JSONObject.parseObject(dbJson);
        List<Long> ids = new ArrayList<>();
        for (Map.Entry<String, Object> entry : dbObject.entrySet()) {
            String dbKey = entry.getKey();
            JSONObject data = JSONObject.parseObject(entry.getValue().toString());
            String id = data.getString("id");
            ids.add(Long.valueOf(id));
            tableStr = tableStr.replaceAll(dbKey, id);
        }

        // 添加数据库关联
        updateProjectAndDatabaseRel(projectId, ids);


        // table 插入数据库 修改 column
        JSONObject tableJson = JSONObject.parseObject(tableStr);
        for (Map.Entry<String, Object> tableEntry : tableJson.entrySet()) {
            String key = tableEntry.getKey();
            String value = tableEntry.getValue().toString();
            ProTable proTable = JSONObject.parseObject(value, ProTable.class);

            proTable.setCreateTime(new Date());
            proTable.setUpdateTime(new Date());
            proTableMapper.insertSelective(proTable);

            columnStr = columnStr.replaceAll(key, proTable.getId().toString());
            fileStr = fileStr.replaceAll(key, proTable.getId().toString());
        }

        // column 插入数据库
        JSONObject columnJson = JSONObject.parseObject(columnStr);
        for (Map.Entry<String, Object> columnEntry : columnJson.entrySet()) {
            String key = columnEntry.getKey();
            String value = columnEntry.getValue().toString();
            ProTableColumn proTableColumn = JSONObject.parseObject(value, ProTableColumn.class);
            proTableColumn.setCreateTime(new Date());
            proTableColumn.setUpdateTime(new Date());
            tableColumnMapper.insertSelective(proTableColumn);
        }

        // file 插入数据库 修改 field fun funArg
        fileStr = fileStr.replaceAll("project_Id", projectId.toString());
        JSONObject fileJson = JSONObject.parseObject(fileStr);
        for (Map.Entry<String, Object> fileEntry : fileJson.entrySet()) {
            String key = fileEntry.getKey();
            String value = fileEntry.getValue().toString();
            ProFile proFile = JSONObject.parseObject(value, ProFile.class);
            proFile.setCreateTime(new Date());
            proFile.setUpdateTime(new Date());
            proFileMapper.insertSelective(proFile);

            fieldStr = fieldStr.replaceAll(key, proFile.getId().toString());
            funStr = funStr.replaceAll(key, proFile.getId().toString());
            funArgStr = funArgStr.replaceAll(key, proFile.getId().toString());
        }

        // fun_oid and fun_nid
        JSONObject funIdDic = new JSONObject();
        // fun 插入 修改 funArg
        JSONObject funJson = JSONObject.parseObject(funStr);
        for (Map.Entry<String, Object> funEntry : funJson.entrySet()) {
            String key = funEntry.getKey();
            String value = funEntry.getValue().toString();
            ProFun proFun = JSONObject.parseObject(value, ProFun.class);
            proFun.setCreateTime(new Date());
            proFun.setUpdateTime(new Date());
            funMapper.insertSelective(proFun);

            String funId = proFun.getId().toString();
            funArgStr = funArgStr.replaceAll(key, funId);

            String oidN = key.split("_")[1];
            String nid = String.format("n_%s", funId);
            funIdDic.put(nid, oidN);
        }

        /**
         * update conf_json to project @ 2022-06-11 lwl
         * ProjectGenerate genControllerAndService()中进行判断替换
          */
        String confJson = funIdDic.toJSONString();
        proProjectMapper.updateConfJsonById(confJson, projectId);

        // funArg插入 修改 funArg
        JSONObject funArgJson = JSONObject.parseObject(funArgStr);
        HashMap<String, String> funArgMap = new HashMap<>();
        for (Map.Entry<String, Object> funArgEntry : funArgJson.entrySet()) {
            String key = funArgEntry.getKey();
            String value = funArgEntry.getValue().toString();

            JSONObject funArgObject = JSONObject.parseObject(value);

            String pid = funArgObject.getString("pid");

            if (pid.contains("fun_arg_")) {
                funArgObject.put("pid", funArgMap.get(pid));
            }

            ProFunArg proFunArg = funArgObject.toJavaObject(ProFunArg.class);
            proFunArg.setCreateTime(new Date());
            proFunArg.setUpdateTime(new Date());
            funArgMapper.insertSelective(proFunArg);

            funArgMap.put(key, proFunArg.getId().toString());

        }
    }


    @Override
    public ServiceCode modify(ProProjectVo proProjectVo) {
        ProProject proProject = BeanUtil.voConvert(proProjectVo, ProProject.class);
        proProject.setUpdateTime(new Date());
        proProjectMapper.updateByPrimaryKeySelective(proProject);

        if (null != proProjectVo.getDbIds()) {
            updateProjectAndDatabaseRel(proProject.getId(), proProjectVo.getDbIds());
        }

        return ServiceCode.SUCCESS;
    }

    private void updateProjectAndDatabaseRel(Long projectId, List<Long> dbIds) {

        // remove rel
        ProProjectDatabaseRelCriteria mProProjectDatabaseRelCriteria = new ProProjectDatabaseRelCriteria();
        mProProjectDatabaseRelCriteria.createCriteria().andProjectIdEqualTo(projectId);
        proProjectDatabaseRelMapper.deleteByExample(mProProjectDatabaseRelCriteria);

        // add rel
        for (Long dbId : dbIds) {
            ProProjectDatabaseRel mProProjectDatabaseRel = new ProProjectDatabaseRel();
            mProProjectDatabaseRel.setCreateTime(new Date());
            mProProjectDatabaseRel.setUpdateTime(new Date());
            mProProjectDatabaseRel.setProjectId(projectId);
            mProProjectDatabaseRel.setDatabaseId(dbId);
            proProjectDatabaseRelMapper.insert(mProProjectDatabaseRel);
        }
    }

    private void genTableRelation(ProProjectVo proProjectVo) {
        List<ProTable> proTableVos = proTableMapper.selectTableByProjectId(proProjectVo.getId());
        Map<String, Object> map = new HashMap<>();
        for (ProTable proTableVo : proTableVos) {

            String curd = proTableVo.getCurd();

            if (StringUtils.isBlank(curd) || "no".equals(curd)) {
                continue;
            }

            String tableName = proTableVo.getName();
            JSONArray array = new JSONArray();

            ProTableColumnCriteria criteria = new ProTableColumnCriteria();
            criteria.createCriteria().andTableIdEqualTo(proTableVo.getId());

            List<ProTableColumn> tableColumns = tableColumnMapper.selectByExample(criteria);

            for (ProTableColumn tableColumn : tableColumns) {
                String relationJson = tableColumn.getRelationJson();
                JSONObject jsonObject = new JSONObject();
                String name = tableColumn.getName();
                jsonObject.put("columnName", name);

                if (StringUtils.isNotBlank(relationJson) && !"no".equals(relationJson)) {
                    jsonObject.put("json", JSONObject.parseObject(relationJson));
                    array.add(jsonObject);
                }
            }

            if (array.size() > 0) {
                map.put(tableName, array);
            }
        }

        DataCache.setDataCache(TABLE_RELATION, map);
    }

    /**
     * 将column注解信息存入缓存
     *
     * @param proProjectVo
     */
    private void genDomainAnnos(ProProjectVo proProjectVo) {

        List<ProTable> proTableVos = proTableMapper.selectTableByProjectId(proProjectVo.getId());
        Map<String, Object> map = new HashMap<>();

        for (ProTable proTableVo : proTableVos) {

            String curd = proTableVo.getCurd();
            if (StringUtils.isBlank(curd) || "no".equals(curd)) {
                continue;
            }

            String tableName = proTableVo.getName();
            JSONArray array = new JSONArray();

            ProTableColumnCriteria criteria = new ProTableColumnCriteria();
            criteria.createCriteria().andTableIdEqualTo(proTableVo.getId());
            List<ProTableColumn> tableColumns = tableColumnMapper.selectByExample(criteria);

            for (ProTableColumn tableColumn : tableColumns) {
                String create = tableColumn.getC();
                String update = tableColumn.getU();
                String verifies = tableColumn.getV();

                JSONObject jsonObject = new JSONObject();
                String name = tableColumn.getName();
                jsonObject.put("columnName", name);

                if (StringUtil.isNotEmpty(verifies) && verifies.trim().length() > 5) {
                    if (StringUtils.isNotBlank(create) && !"no".equals(create)) {
                        jsonObject.put("c", JSONArray.parse(verifies));
                    }
                    if (StringUtils.isNotBlank(update) && !"no".equals(update)) {
                        jsonObject.put("u", JSONArray.parse(verifies));
                    }
                    array.add(jsonObject);
                }

            }

            if (array.size() > 0) {
                map.put(tableName, array);
            }
        }


        DataCache.setDataCache(DOMAIN_ANNOTATIONS, map);
    }


    @Override
    public BaseRes<String> genProject(ProProjectVo proProjectVo) {

        // CURD表关联配置生成
        genTableRelation(proProjectVo);
        //注解信息生成
        genDomainAnnos(proProjectVo);

        ProjectGenerate proGen = null;

        if ("micro".equalsIgnoreCase(proProjectVo.getProType())) {
            proGen = SpringContextUtil.getBean(MicroProjectGenerate.class);
        } else if ("simple".equalsIgnoreCase(proProjectVo.getProType())) {
            proGen = SpringContextUtil.getBean(SimpleProjectGenerate.class);
        }

        if (null != proGen) {
            try {
                return proGen.genProject(proProjectVo);
            } catch (Exception e) {
                e.printStackTrace();
                BaseRes<String> res = new BaseRes<>();
                res.setServiceCode(ServiceCode.FAILED);
                res.setMsg(e.getMessage());
            }
        }

        return new BaseRes<>(ServiceCode.SUCCESS);
//
//		Long id = proProjectVo.getId();
//
//		LOG.info("id={}", id);
//		ProProject proProject = proProjectMapper.selectByPrimaryKey(id);
//
//		LOG.info("proProject={}", JSONObject.toJSONString(proProject));
//
//		// 使用本传入地址生成
//		if(StringUtils.isNotEmpty(proProjectVo.getLocalPath())) {
//			proProject.setLocalPath(proProjectVo.getLocalPath());
//		}
//
//		BaseRes<String> res = new BaseRes<String>();
//
//		try {
//			Map<String, String> commValidMap = getValidAndClassPath(proProject);
//			// 创建util
//			ProjectGenUtil projectGenUtil = new ProjectGenUtil(proProject);
//
//			/**
//			 * 初始被创建项目
//			 */
//			projectGenUtil.genProjectBase();
//			LOG.info("projectGenUtil.genProjectBase() ...");
//
//			/**
//			 * 生成 domain
//			 */
//			genDomain(projectGenUtil, proProject);
//			LOG.info("genDomain(projectGenUtil, proProject) ...");
//
//			/**
//			 * 生成Controller 控制器 和 Service
//			 */
//			genControllerAndService(projectGenUtil, proProject, commValidMap);
//			LOG.info("genControllerAndService(projectGenUtil, proProject, commValidMap) ...");
//
//			/**
//			 * 生成 vo 类
//			 */
//			getVo(projectGenUtil, proProject, commValidMap);
//			LOG.info("getVo(projectGenUtil, proProject, commValidMap) ...");
//
//			res.setServiceCode(ServiceCode.SUCCESS);
//		} catch (Exception e) {
//			e.printStackTrace();
//			res.setServiceCode(ServiceCode.FAILED);
//			res.setMsg(e.getMessage());
//		}
//		return res;
        // replace package name from project file, folder

    }

    private void genDomain(ProjectGenUtil projectGenUtil, ProProject proProject) throws SQLException {
        // db list
        ProProjectDatabaseRelCriteria ppdrc = new ProProjectDatabaseRelCriteria();
        ppdrc.createCriteria().andProjectIdEqualTo(proProject.getId());
        List<ProProjectDatabaseRel> proDbs = proProjectDatabaseRelMapper.selectByExample(ppdrc);

        List<Long> dbIds = new ArrayList<Long>();
        for (ProProjectDatabaseRel pdr : proDbs) {
            dbIds.add(pdr.getDatabaseId());
        }
        if (!CollectionUtils.isEmpty(dbIds)) {
            ProDatabaseCriteria pdc = new ProDatabaseCriteria();
            pdc.createCriteria().andIdIn(dbIds);
            List<ProDatabase> dababases = proDatabaseMapper.selectByExample(pdc);

            if (dababases.size() > 0) {
                ProDatabase database = dababases.get(0);

                List<ProTable> tables = proTableMapper.selectTableAndColumnByDbId(Arrays.asList(database.getId()));

                String ignoreTables = proProject.getIgnoreTables(); // 忽略生成表
                if (StringUtils.isNotEmpty(ignoreTables)) {
                    tables = tables.stream().filter(table -> ignoreTables.indexOf("\"" + table.getId() + "\"") < 0).collect(Collectors.toList());
                }

                /**
                 * 暂时支持一个数据库 mapper/entity
                 */
                projectGenUtil.initH2Database(tables, database);
                projectGenUtil.genJavaFromDb(tables, database);
            }
        }
    }

    private Map<String, String> getValidAndClassPath(ProProject proProject) {
        // 查出所有valid
        CommValidateCriteria mCommValidateCriteria = new CommValidateCriteria();
        mCommValidateCriteria.createCriteria().andProIdIsNull();
        mCommValidateCriteria.or().andProIdEqualTo(proProject.getId());
        List<CommValidate> validObjs = commValidateMapper.selectByExample(mCommValidateCriteria);

        Map<String, String> map = new HashMap<>();
        for (CommValidate cv : validObjs) {
            map.put(cv.getName(), cv.getClassPath());
        }

        return map;
    }

    private void genControllerAndService(ProjectGenUtil projectGenUtil, ProProject proProject, Map<String, String> commValidMap) throws Exception {
        ProFileCriteria mProFileCriteria = new ProFileCriteria();
        mProFileCriteria.createCriteria()
                .andFileTypeEqualTo(TypeEnum.FileTypeEnum.controller.name())
                .andProjectIdEqualTo(proProject.getId());
        mProFileCriteria.setOrderByClause("id");
        List<ProFile> controllerList = proFileMapper.selectFileAndModule(mProFileCriteria);

        // 加载方法列表
        for (ProFile file : controllerList) {
            ProFunCriteria mProFunCriteria = new ProFunCriteria();
            mProFunCriteria.createCriteria().andCidEqualTo(file.getId());
            mProFunCriteria.setOrderByClause("id");
            List<ProFun> funs = funMapper.selectByExample(mProFunCriteria);

            /**
             * 1、加载参数
             * 2、方法返回值类加入到file的import中
             * 3、将参数的类类型加入到 file import中
             */
            for (ProFun fun : funs) {
                List<ProFunArg> args = funArgMapper.fetchFunArgsByFunId(fun.getId());
                fun.setArgs(args);


                List<Long> voIds = new ArrayList<>();

                /**
                 * 将参数的类类型加入到 file的import中
                 */
                if (!org.springframework.util.CollectionUtils.isEmpty(args)) {
                    FileIdsAndType argFrt = projectGenUtil.getArgTypes(args);
                    file.getImportTypes().addAll(argFrt.getTypePaths());

                    voIds.addAll(argFrt.getTypeIds());
                }
                /**
                 * 方法返回值类加入到file的import中
                 */
                if (null != fun.getResVoId()) {
                    LOG.info("returnVoJson={}", fun.getReturnVo());
                    FileIdsAndType frt = projectGenUtil.getFunReturnType(fun.getReturnVo());
                    file.getImportTypes().addAll(frt.getTypePaths());

                    voIds.addAll(frt.getTypeIds());
                    voIds.add(fun.getResVoId());

                    // 导入import
                    importTypeToFile(voIds, file, projectGenUtil);
                }
            }

            file.setFuns(funs);
        }
        projectGenUtil.genController(proProject, controllerList, commValidMap);
        projectGenUtil.genService(proProject, controllerList);
    }

    private void getVo(ProjectGenUtil projectGenUtil, ProProject proProject, Map<String, String> commValidMap) throws FileNotFoundException, IOException {

        /**
         * 生成 Vo验证规则 - 加载不能的验证规则
         */
        ProFileCriteria voCriteria = new ProFileCriteria();
        voCriteria.createCriteria()
                .andFileTypeEqualTo(TypeEnum.FileTypeEnum.vo.name())
                .andProjectIdEqualTo(proProject.getId());
        List<ProFile> voList = proFileMapper.selectFileAndModule(voCriteria);
        for (ProFile file : voList) {
            ProFieldCriteria fieldCriteria = new ProFieldCriteria();
            fieldCriteria.setOrderByClause("id");
            fieldCriteria.createCriteria().andFileIdEqualTo(file.getId());

            List<ProField> fields = proFieldMapper.selectByExample(fieldCriteria);

            file.setFields(fields);

            FileIdsAndType frt = projectGenUtil.getFieldTypes(fields);
            file.getImportTypes().addAll(frt.getTypePaths());

            // 导入import
            importTypeToFile(frt.getTypeIds(), file, projectGenUtil);

            List<ProField> validateMethods = new ArrayList<>();
            file.setValidateMethods(validateMethods);

            // table validate
            if (null != file.getSuperId()) {
                // 添加table 需要验证的 方法 validateMethods
                ProTableColumnCriteria criteria = new ProTableColumnCriteria();
                criteria.createCriteria()
                        .andTableIdEqualTo(file.getSuperId());
                List<ProTableColumn> columns = tableColumnMapper.selectByExample(criteria);

                Set<String> columnSet = new HashSet<>();
                for (ProTableColumn c : columns) {
                    columnSet.add(c.getName());
                }

                // 找出当前vo 所有的
                ProFunArgCriteria argCriteria = new ProFunArgCriteria();
                argCriteria.createCriteria()
                        .andArgTypeEqualTo(TypeEnum.FunArgType.vo.name())
                        .andArgTypeIdEqualTo(file.getId());
                List<ProFunArg> args = funArgMapper.selectByExample(argCriteria);

                if (CollectionUtils.isEmpty(args)) {
                    continue;
                }

                List<Long> pids = new ArrayList<>();
                for (ProFunArg arg : args) {
                    pids.add(arg.getId());
                }

                argCriteria.clear();
                argCriteria.createCriteria()
                        .andPidIn(pids);
                args = funArgMapper.selectByExample(argCriteria);
                Map<String, ProFunArg> argMap = new HashMap<String, ProFunArg>();
                for (ProFunArg arg : args) {
                    argMap.put(arg.getName(), arg);
                }

                // 获取 表格和参数列表的 交集
                columnSet.retainAll(argMap.keySet());
                for (String ss : columnSet) {
                    ProFunArg arg = argMap.get(ss);
                    ProField mProField = new ProField();
                    mProField.setName(arg.getName());
                    mProField.setDataType(arg.getArgTypeName());
                    validateMethods.add(mProField);
                }
            }
        }

        // 字段有哪些验证， 验证有哪些验证组
        for (ProFile file : voList) {

            ProFunArgCriteria mProFunArgCriteria = new ProFunArgCriteria();
            mProFunArgCriteria.createCriteria()
                    .andArgTypeIdEqualTo(file.getId())
                    .andArgTypeEqualTo(TypeEnum.FunArgType.vo.name());
            mProFunArgCriteria.setOrderByClause("id");
            List<ProFunArg> voArgs = funArgMapper.selectByExample(mProFunArgCriteria);

            // property, valid
            final Map<String, Map<String, Set<String>>> propertyValid = file.getPropertyValid() != null ? file.getPropertyValid() : new HashMap<>();
            file.setPropertyValid(propertyValid);

            voArgs.forEach(arg -> {

                Long funId = arg.getFunId();
                ProFun fun = funMapper.selectByPrimaryKey(funId);
                ProFile controller = proFileMapper.selectByPrimaryKey(fun.getCid());

                System.out.println("controller=" + controller + ", fun=" + fun);

                // controller + fun
                String validateGroupName = controller.getName() + "_" + fun.getFunName();

                ProFunArgCriteria funArgCriteria = new ProFunArgCriteria();
                funArgCriteria.createCriteria()
                        .andPidEqualTo(arg.getId())
                        .andValidIsNotNull();
                List<ProFunArg> childArgs = funArgMapper.selectByExample(funArgCriteria);

                childArgs.forEach(carg -> {

                    String pName = carg.getName();

                    // valid,group
                    Map<String, Set<String>> validGroup = propertyValid.get(pName);
                    if (validGroup == null) {
                        validGroup = new HashMap<>();
                        propertyValid.put(pName, validGroup);
                    }

                    String validStr = carg.getValid();
                    if (StringUtils.isNotBlank(validStr)) {
                        JSONArray arr = JSONArray.parseArray(validStr);

                        for (int i = 0; i < arr.size(); i++) {
                            String key = arr.getString(i);

                            Set<String> groupSet = validGroup.get(key);
                            if (null == groupSet) {
                                groupSet = new HashSet<>();
                                validGroup.put(key, groupSet);
                            }
                            groupSet.add(validateGroupName);
                        }
                    }
                });
            });
        }

        projectGenUtil.genVo(proProject, voList, commValidMap);
    }

    private void importTypeToFile(List<Long> voIds, ProFile file, ProjectGenUtil projectGenUtil) {
        // 提取
        if (!org.springframework.util.CollectionUtils.isEmpty(voIds)) {
            ProFileCriteria fileCriteria = new ProFileCriteria();
            fileCriteria.createCriteria().andIdIn(voIds);
            List<ProFile> fileList = proFileMapper.selectFileAndModule(fileCriteria);

            LOG.info("fileList={}", fileList.size());

            Set<String> fileTypes = projectGenUtil.getFileTypes(fileList);
            file.getImportTypes().addAll(fileTypes);
        }
    }

    @Override
    public BaseRes<DataPageWrapper<ProModuleVo>> moduleList(Integer currPage, Integer pageSize, ProModuleVo proModuleVo) {

        BaseRes<DataPageWrapper<ProModuleVo>> res = new BaseRes<>();
        res.setData(new DataPageWrapper<ProModuleVo>());
        res.getData().setCurrPage(currPage);
        res.getData().setPageSize(pageSize);

        ProModuleCriteria example = new ProModuleCriteria();
        int mysqlLength = pageSize;
        int mysqlOffset = (currPage - 1) * mysqlLength;

        example.setMysqlLength(mysqlLength);
        example.setMysqlOffset(mysqlOffset);

        ProModuleCriteria.Criteria mCriteria = example.createCriteria();
        if (StringUtils.isNotEmpty(proModuleVo.getName())) {
            mCriteria.andNameLike(proModuleVo.getName() + "%");
        }

        long totalCount = proModuleMapper.countByExample(example);
        res.getData().setTotalCount(totalCount);
        if (totalCount > 0) {
            List<ProModule> proModuleList = proModuleMapper.selectByExample(example);
            List<ProModuleVo> rows = BeanUtil.voConvertList(proModuleList, ProModuleVo.class);
            res.getData().setRows(rows);
        }
        return res;
    }

    @Override
    public ProModuleVo moduleDetail(Long id) {
        ProModule mProModule = proModuleMapper.selectByPrimaryKey(id);
        if (mProModule != null) {
            ProModuleVo mProModuleVo = BeanUtil.voConvert(mProModule, ProModuleVo.class);
            return mProModuleVo;
        }
        return null;
    }

    @Override
    public boolean delModule(Long id) {

        // remove file or module

        return 0 < proModuleMapper.deleteByPrimaryKey(id);
    }

    @Override
    public ServiceCode addModule(ProModuleVo proModuleVo) {

        proModuleVo.setCreateTime(new Date());
        proModuleVo.setUpdateTime(new Date());

        return 0 < proModuleMapper.insertSelective(proModuleVo) ? ServiceCode.SUCCESS : ServiceCode.FAILED;
    }

    @Override
    public ServiceCode modifyModule(ProModuleVo proModuleVo) {

        proModuleVo.setUpdateTime(new Date());
        return 0 < proModuleMapper.updateByPrimaryKeySelective(proModuleVo) ? ServiceCode.SUCCESS : ServiceCode.FAILED;
    }

    @Override
    public BaseRes<List<ProProjectVo>> projectList() {

        BaseRes<List<ProProjectVo>> res = new BaseRes<List<ProProjectVo>>();
        ProProjectCriteria proProjectCriteria = new ProProjectCriteria();
        proProjectCriteria.createCriteria().andDelFlagEqualTo(0);
        List<ProProject> proProjectList = proProjectMapper.selectByExample(proProjectCriteria);
        List<ProProjectVo> rows = new ArrayList<ProProjectVo>();
        for (ProProject project : proProjectList) {
            ProProjectVo mProProjectVo = new ProProjectVo();
            mProProjectVo.setId(project.getId());
            mProProjectVo.setName(project.getName());
            rows.add(mProProjectVo);
        }
        res.setServiceCode(ServiceCode.SUCCESS);
        res.setData(rows);
        return res;

    }

    @Override
    public BaseRes<List<ProModuleVo>> projectModuleList(Long projectId) {
        BaseRes<List<ProModuleVo>> res = new BaseRes<List<ProModuleVo>>();
        ProModuleCriteria mProModuleCriteria = new ProModuleCriteria();
        mProModuleCriteria.createCriteria().andProjectIdEqualTo(projectId);
        List<ProModule> proProjectList = proModuleMapper.projectModuleList(projectId);
        List<ProModuleVo> rows = BeanUtil.voConvertListIgnore(proProjectList, ProModuleVo.class, "createTime", "updateTime");
        return new BaseRes<>(rows, ServiceCode.SUCCESS);
    }

    /**
     * -----微服务 --
     */

    @Override
    public BaseRes<List<ProMicroServiceVo>> projectMicroServiceList(Long projectId) {
        ProMicroServiceCriteria example = new ProMicroServiceCriteria();
        example.createCriteria().andDelFlagEqualTo(0).andProjectIdEqualTo(projectId);
        List<ProMicroService> list = microServiceMapper.selectByExample(example);
        List<ProMicroServiceVo> voList = BeanUtil.voConvertListIgnore(list, ProMicroServiceVo.class);
        return new BaseRes<>(voList, ServiceCode.SUCCESS);
    }

    @Override
    public BaseRes<String> delMicroService(Long id) {
        ProMicroService record = new ProMicroService();
        record.setId(id);
        record.setDelFlag(1);
        record.setUpdateTime(new Date());
        microServiceMapper.updateByPrimaryKeySelective(record);
        return new BaseRes<>(ServiceCode.SUCCESS);
    }

    @Override
    public BaseRes<String> addMicroService(ProMicroServiceVo proMicroServiceVo) {
        Date d = new Date();
        proMicroServiceVo.setUpdateTime(d);
        proMicroServiceVo.setCreateTime(d);
        microServiceMapper.insertSelective(proMicroServiceVo);
        return new BaseRes<>(ServiceCode.SUCCESS);
    }

    @Override
    public BaseRes<String> modifyMicroService(ProMicroServiceVo proMicroServiceVo) {
        proMicroServiceVo.setUpdateTime(new Date());
        microServiceMapper.updateByPrimaryKeySelective(proMicroServiceVo);
        return new BaseRes<>(ServiceCode.SUCCESS);
    }

    @Override
    public BaseRes<String> exportGenConfig(ProProjectVo proProjectVo) {

        Long projectId = proProjectVo.getId();
        String localPath = proProjectVo.getLocalPath();
        String comment = proProjectVo.getComment();

        String exportType = proProjectVo.getExportType();

        ProProject proProject = proProjectMapper.selectByPrimaryKey(projectId);

        String artifactId = proProject.getArtifactId();
        String proType = proProject.getProType();

        if (!"micro".equals(proType)) {
            // 非微服务使用 _
            artifactId = artifactId.replaceAll("-", "_");
        }

        String genFolderPath = localPath + "/" + artifactId + "/file/";

        // 更新 comment
        proProject.setComment(comment);
        proProject.setExportType(exportType);
        proProjectMapper.updateByPrimaryKeySelective(proProject);

        // 生成auto数据库配置
        genDatabaseConfig(genFolderPath, proProject);

        // 导出项目sql语句
        exportDatabaseStructure(projectId, genFolderPath);

        return new BaseRes<>(ServiceCode.SUCCESS);

    }

    @Override
    public BaseRes<String> getTemplateData() throws IOException {
        //[{value:"",label:"",info:{},databaseData:[{dbName:"",},{}]},{}]

        /**
         * 1.获取template下所有文件
         * 2.读取对应项目下配置文件
         * 3.获取项目基本信息，数据库信息
         */

        JSONArray dataArr = new JSONArray();

        URL resource = ProProjectServiceImpl.class.getResource("/template");
        URLConnection urlConnection = resource.openConnection();

        // 判断是文件还是jar包

        if (urlConnection instanceof FileURLConnection) {
            getTemplateFolderByFile(resource.getPath(), dataArr);
        } else if (urlConnection instanceof JarURLConnection) {
            getTemplateFolderByJar((JarURLConnection) urlConnection, dataArr);
        }

        return new BaseRes<>(dataArr.toJSONString(), ServiceCode.SUCCESS);
    }

    private void getTemplateFolderByJar(JarURLConnection jarURLConnection, JSONArray dataArr) throws IOException {

        TreeMap<String, String> templateCache = DataCache.getTemplateCache();

        if (null == templateCache) {
            templateCache = getTemplateFolderList(jarURLConnection);
        }

        Set<String> names = templateCache.keySet();

        for (String name : names) {

            LOG.info("folderName={}", name);

            addTemplateData(name, dataArr);
        }
    }


    private TreeMap<String, String> getTemplateFolderList(JarURLConnection jarURLConnection) throws IOException {

        JarFile jarFile = jarURLConnection.getJarFile();
        Enumeration<JarEntry> entries = jarFile.entries();

        TreeMap<String, String> map = new TreeMap<>();

        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            String folderName = entry.getName();
            if (folderName.startsWith(jarURLConnection.getEntryName()) && folderName.endsWith("/")) {
                // 只获取子级目录
                if ("template/".equals(folderName)) continue;
                String substring = folderName.substring("template/".length());
                String substring1 = substring.substring(0, substring.indexOf("/"));
                map.put(substring1, substring1);
            }
        }

        jarFile.close();
        DataCache.setTemplateCache(map);

        return map;
    }


    private void getTemplateFolderByFile(String path, JSONArray dataArr) {

        File file = new File(path);

        if (!file.exists()) {
            return;
        }

        File[] templateList = file.listFiles();

        for (File templateItem : templateList) {

            if (templateItem.isDirectory()) {
                addTemplateData(templateItem.getName(), dataArr);
            }
        }
    }

    private void addTemplateData(String name, JSONArray dataArr) {
        JSONObject templateObj = new JSONObject();

        templateObj.put("value", name);

        String configStr = readFileInResource("/template/" + name + "/file/dataConfig.json");
        JSONObject configJson = JSONObject.parseObject(configStr);
        JSONObject project = configJson.getJSONObject("project");
        templateObj.put("info", project.toJSONString());

        String comment = project.getString("comment");
        templateObj.put("label", comment);

        String database = configJson.getString("database");
        templateObj.put("databaseData", database);

        dataArr.add(templateObj);
    }


    private void exportDatabaseStructure(Long projectId, String path) {

        List<ProDatabase> proDatabases = proDatabaseMapper.selectByProjectId(projectId);

        for (ProDatabase proDatabase : proDatabases) {
            String genPath = path + proDatabase.getDbName() + "_init.json";
            String host = proDatabase.getHostname();
            String port = proDatabase.getPort();
            String username = proDatabase.getUsername();
            String password = proDatabase.getPassword();
            String dbName = proDatabase.getDbName();

            List<Map<String, Object>> tables = DBUtil.exeQuerySql("show table status", host, Integer.parseInt(port), username, password, dbName);

            JSONArray dbArr = new JSONArray();

            for (Map<String, Object> table : tables) {
                String tabName = table.get("Name").toString();
                List<Map<String, Object>> tableData = DBUtil.exeQuerySql("show create table " + tabName, host, Integer.parseInt(port), username, password, dbName);
                if (tableData.size() == 0) {
                    continue;
                }

                String tableCreateSql = tableData.get(0).get("Create Table").toString();

                // 如果包含自增 ID 则去掉 判断最后一行是否包含 AUTO_INCREMENT 关键字
                String[] tableCreateSqlArr = tableCreateSql.split("\n");
                if (tableCreateSqlArr[tableCreateSqlArr.length - 1].contains("AUTO_INCREMENT")) {
                    String[] tableSplit = tableCreateSql.split("AUTO_INCREMENT");

                    String startSql = tableCreateSql.substring(0, tableCreateSql.lastIndexOf("AUTO_INCREMENT"));

                    String auto_increment = tableSplit[tableSplit.length - 1];

                    String[] autoIncrementSplit = auto_increment.split(" ");

                    StringBuilder stringEnd = new StringBuilder();

                    // 第一个去掉
                    for (int i = 0; i < autoIncrementSplit.length; i++) {
                        if (i == 0) {
                            continue;
                        }

                        stringEnd.append(" ").append(autoIncrementSplit[i]);
                    }

                    tableCreateSql = startSql + stringEnd.toString();
                }

                String tableExists = "DROP TABLE IF EXISTS `" + tabName + "`;";
                dbArr.add(tableExists);
                dbArr.add(tableCreateSql);
            }

            //创建文件
            createFile(genPath, dbArr.toJSONString());

        }
    }

    private void genDatabaseConfig(String path, ProProject proProject) {

        Long projectId = proProject.getId();
        String genPath = path + "dataConfig.json";

        JSONObject configMap = new JSONObject(true);

        ProProject pro = BeanUtil.voConvertIgnore(proProject, ProProject.class, "local_path", "del_flag");

        configMap.put("project", objectToJSONObject(pro));

        // 获取 module project_id
        ProModuleCriteria proModuleCriteria = new ProModuleCriteria();
        proModuleCriteria.createCriteria().andProjectIdEqualTo(projectId);
        List<ProModule> proModules = proModuleMapper.selectByExample(proModuleCriteria);

        JSONObject moduleJSONObject = new JSONObject(true);

        for (ProModule proModule : proModules) {
            JSONObject moduleObject = objectToJSONObject(proModule);
            moduleObject.put("projectId", "project_Id");
            if (null != proModule.getMicroId() && 0 != proModule.getMicroId()) {
                moduleObject.put("microId", genIdKey("micro", proModule.getMicroId()));
            }

            moduleJSONObject.put(genIdKey("module", proModule.getId()), moduleObject);
        }

        configMap.put("module", moduleJSONObject);


        //获取微服务 project_id
        ProMicroServiceCriteria proMicroServiceCriteria = new ProMicroServiceCriteria();
        proMicroServiceCriteria.createCriteria().andProjectIdEqualTo(projectId);
        List<ProMicroService> proMicroServices = microServiceMapper.selectByExample(proMicroServiceCriteria);

        JSONObject microJSONObject = new JSONObject(true);
        for (ProMicroService proMicroService : proMicroServices) {
            JSONObject microObject = objectToJSONObject(proMicroService);
            microObject.put("projectId", "project_Id");

            microJSONObject.put(genIdKey("micro", proMicroService.getId()), microObject);
        }
        configMap.put("micro", microJSONObject);

        // 获取数据库 label value
        List<ProDatabase> proDatabases = proDatabaseMapper.selectByProjectId(projectId);
        JSONArray databaseJSONArray = new JSONArray();
        for (ProDatabase database : proDatabases) {

            JSONObject databaseObject = new JSONObject(true);

            databaseObject.put("label", database.getDbName());
            databaseObject.put("comment", database.getComment());
            databaseObject.put("rbac", database.getRbac());
            databaseObject.put("value", genIdKey("database", database.getId()));

            databaseJSONArray.add(databaseObject);
        }
        configMap.put("database", databaseJSONArray);


        // 获取表 database_id
        JSONObject tableJSONObject = new JSONObject(true);
        List<ProTable> proTableVos = proTableMapper.selectTableByProjectId(projectId);
        for (ProTable proTableVo : proTableVos) {
            JSONObject tableObject = objectToJSONObject(proTableVo);
            tableObject.put("databaseId", genIdKey("database", proTableVo.getDatabaseId()));
            tableJSONObject.put(genIdKey("table", proTableVo.getId()), tableObject);
        }
        configMap.put("table", tableJSONObject);

        // 获取表字段 table_id
        JSONObject tableColumnJSONObject = new JSONObject(true);
        List<ProTableColumn> tableColumns = tableColumnMapper.selectByProjectId(projectId);
        for (ProTableColumn proTableColumn : tableColumns) {
            JSONObject columnObject = objectToJSONObject(proTableColumn);
            columnObject.put("tableId", genIdKey("table", proTableColumn.getTableId()));
            tableColumnJSONObject.put(genIdKey("column", proTableColumn.getId()), columnObject);
        }
        configMap.put("column", tableColumnJSONObject);


        // 获取文件 controller vo    project_id module_id micro_id table_id
        JSONObject fileJSONObject = new JSONObject(true);
        List<ProFile> files = proFileMapper.selectByProjectId(projectId);
        for (ProFile file : files) {
            JSONObject fileObject = objectToJSONObject(file);
            fileObject.put("projectId", "project_Id");

            if (null != file.getModuleId()) {
                fileObject.put("moduleId", genIdKey("module", file.getModuleId()));
            }

            if (null != file.getMicroId() && 0 != file.getMicroId()) {
                fileObject.put("microId", genIdKey("micro", file.getMicroId()));
            }

            if (null != file.getSuperId() && 0 != file.getSuperId()) {
                fileObject.put("superId", genIdKey("table", file.getSuperId()));
            }

            fileJSONObject.put(genIdKey("file", file.getId()), fileObject);
        }
        configMap.put("file", fileJSONObject);

        //获取字段 file_id
        JSONObject fieldJSONObject = new JSONObject(true);
        List<ProField> proFields = proFieldMapper.selectByProjectId(projectId);
        for (ProField proField : proFields) {
            JSONObject fieldObject = objectToJSONObject(proField);
            fieldObject.put("fileId", genIdKey("file", proField.getFileId()));
            fieldJSONObject.put(genIdKey("field", proField.getId()), fieldObject);
        }
        configMap.put("field", fieldJSONObject);

        // 获取方法 file_id
        JSONObject funJSONObject = new JSONObject(true);
        List<ProFun> funs = funMapper.selectByProjectId(projectId);
        for (ProFun fun : funs) {
            JSONObject funObject = objectToJSONObject(fun);

            funObject.put("cid", genIdKey("file", fun.getCid()));

            // return vo
            String returnVo = fun.getReturnVo();
            out:
            if (StringUtils.isNotBlank(returnVo) && !"{}".equals(returnVo)) {
                JSONObject returnObject = JSONObject.parseObject(returnVo);
                Integer id = returnObject.getInteger("id");
                if (id == null) break out;
                JSONObject next = returnObject.getJSONObject("next");

                String nextId = null;
                if (null != next && null != (nextId = next.getString("id"))) {
                    next.put("id", genIdKey("file", nextId));
                    returnObject.put("next", next);
                } else {
                    returnObject.put("id", genIdKey("file", id));
                }

                funObject.put("returnVo", returnObject.toJSONString());
            }

            // res_vo_id 如果为1或2 则是数据库默认数据 不用修改
            Long resVoId = fun.getResVoId();
            if (null != resVoId && resVoId > 2) {
                funObject.put("resVoId", genIdKey("file", resVoId));
            }

            funJSONObject.put(genIdKey("fun", fun.getId()), funObject);
        }
        configMap.put("fun", funJSONObject);

        // 获取方法参数 fun_id file_id fun_arg_id
        JSONObject funArgJSONObject = new JSONObject(true);
        List<ProFunArg> proFunArgs = funArgMapper.selectByProjectId(projectId);
        for (ProFunArg proFunArg : proFunArgs) {
            JSONObject funArgObject = objectToJSONObject(proFunArg);
            funArgObject.put("funId", genIdKey("fun", proFunArg.getFunId()));

            Long pid = proFunArg.getPid();
            if (null != pid && 0 != pid) {
                funArgObject.put("pid", genIdKey("fun_arg", pid));
            }

            String argType = proFunArg.getArgType();
            Long argTypeId = proFunArg.getArgTypeId();

            if ("vo".equals(argType)) {
                funArgObject.put("argTypeId", genIdKey("file", argTypeId));
            }

            funArgJSONObject.put(genIdKey("fun_arg", proFunArg.getId()), funArgObject);
        }
        configMap.put("funArg", funArgJSONObject);


        //导出至项目文件下

        LOG.info("genPath={}", genPath);
        // 检测是否存在 存在则删除

        createFile(genPath, configMap.toJSONString());
    }

    private String genIdKey(String type, Object id) {
        return String.format("%s_%s_", type, id);
    }

    // 创建文件
    private void createFile(String path, String data) {
        File file = new File(path);
        // 清空文件
        if (file.exists()) {
            file.delete();
        }

        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }

        try {
            file.createNewFile();
            OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            osw.write(data);
            osw.flush();
            osw.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    private JSONObject objectToJSONObject(Object o) {
        JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(o));

        jsonObject.remove("id");
        jsonObject.remove("createTime");
        jsonObject.remove("updateTime");

        return jsonObject;
    }


    public static void main(String[] args) {
        System.out.println(String.format("%s_%s_", "fdsf", 121l));
    }


}
